package com.pz.cloud.framework.model;

import com.pz.cloud.framework.base.model.Pageable;
import com.pz.cloud.framework.util.BizUtil;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.enums.DataScope;
import org.jeecg.common.handler.DataScopeHandler;
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/**
 * 抽象sql装饰类
 * @author 3hmzz
 */
public abstract class AbstractSqlBuilder {
    protected StringBuilder sql;
    protected StringBuilder countSql;
    protected Map<String,Object> parmMap;//参数
    protected Pageable page;//分页model
    protected Class returnType;//返回值类型
    protected String orderBy;//排序

    public AbstractSqlBuilder(){
        sql = new StringBuilder();
    }
    public AbstractSqlBuilder(String initSql){
        sql = new StringBuilder(initSql);
    }
    public AbstractSqlBuilder appendTable(Class cls){
        this.sql.append(BizUtil.getTableName(cls));
        return this;
    }
    public AbstractSqlBuilder append(String sql){
        this.sql.append(sql);
        return this;
    }
    public AbstractSqlBuilder from(String tableName,String alias){
        this.sql.append(" from ").append(tableName).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder innerJoin(String tableName,String alias){
        this.sql.append(" inner join ").append(tableName).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder leftJoin(String tableName,String alias){
        this.sql.append(" left join ").append(tableName).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder rightJoin(String tableName,String alias){
        this.sql.append(" right join ").append(tableName).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder innerJoin(Class tableCls,String alias){
        this.sql.append(" inner join ").append(BizUtil.getTableName(tableCls)).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder leftJoin(Class tableCls,String alias){
        this.sql.append(" left join ").append(BizUtil.getTableName(tableCls)).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder rightJoin(Class tableCls,String alias){
        this.sql.append(" right join ").append(BizUtil.getTableName(tableCls)).append(" ");
        if(StringUtils.isNotEmpty(alias)){
            this.sql.append(alias);
        }
        return this;
    }
    public AbstractSqlBuilder on(String sql){
        this.sql.append(" on ").append(sql);
        return this;
    }


    public Map<String,Object> getParmMap(){
        if(parmMap==null){
            parmMap = new HashMap<>();
        }
        return parmMap;
    }
    public AbstractSqlBuilder setParms(String key,Object value){
        getParmMap().put(key,value);
        return this;
    }
    public AbstractSqlBuilder setParms(Map<String,Object> parmMap){
        getParmMap().putAll(parmMap);
        return this;
    }
    public AbstractSqlBuilder setParmsLike(String key,Object value){
        getParmMap().put(key,"%"+value+"%");
        return this;
    }
    public AbstractSqlBuilder page(Pageable page){
        this.page = page;
        return this;
    }
    public AbstractSqlBuilder returnType(Class returnType){
        this.returnType = returnType;
        return this;
    }
    public AbstractSqlBuilder filterDataScope(String alias){
        String tableAlias = alias == null ? "" : alias + ".";

        if(SqlQueryGenerator.hasRule(DataScope.全部.getCode())){
        }else  if(SqlQueryGenerator.hasRule(DataScope.组织树.getCode())){
            this.append(" and ").append(tableAlias).append("creator_id in (select user_id from sys_user_depart where dep_id in( :deptId))")
                    .setParms("deptId", BizUtil.getUser().getDeptTreeIdList());
        }else if(SqlQueryGenerator.hasRule(DataScope.组织.getCode())){
            this.append(" and ").append(tableAlias).append("creator_id in (select user_id from sys_user_depart where dep_id in( :deptId))")
                    .setParms("deptId", BizUtil.getUser().getDeptIdList());
//            and os.id in (select society_id from org_society_user where user_id = :userId)
        }else if(SqlQueryGenerator.hasRule(DataScope.个人.getCode())){
            this.append(" and ").append(tableAlias).append("creator_id = :creatorId").setParms("creatorId", BizUtil.getUserId());
        }
        return this;
    }

    /**
     * @param alias
     * @param column  权限控制的字段
     * @return
     */
    public AbstractSqlBuilder filterDataScope(String alias,String column){
        if(StringUtils.isEmpty(column)){
            return filterDataScope(alias);
        }
        String tableAlias = alias == null ? "" : alias + ".";
        if(SqlQueryGenerator.hasRule(DataScope.全部.getCode())){
        }else  if(SqlQueryGenerator.hasRule(DataScope.组织树.getCode())){
            this.append(" and (").append(tableAlias).append(" creator_id in (select user_id from sys_user_depart where dep_id in( :deptId))")
                    .append(" or ").append(tableAlias).append(column).append(" in (select user_id from sys_user_depart where dep_id in( :deptId)) )")
                    .setParms("deptId", BizUtil.getUser().getDeptTreeIdList());
        }else if(SqlQueryGenerator.hasRule(DataScope.组织.getCode())){
            this.append(" and (").append(tableAlias).append(" creator_id in (select user_id from sys_user_depart where dep_id in( :deptId))")
                    .append(" or ").append(tableAlias).append(column).append(" in (select user_id from sys_user_depart where dep_id in( :deptId)) )")
                    .setParms("deptId", BizUtil.getUser().getDeptIdList());
//            and os.id in (select society_id from org_society_user where user_id = :userId)
        }else if(SqlQueryGenerator.hasRule(DataScope.个人.getCode())){
            this.append(" and (").append(tableAlias).append(" creator_id = :creatorId")
                    .append(" or ").append(tableAlias).append(column).append(" = :creatorId )")
                    .setParms("creatorId", BizUtil.getUserId());
        }
        return this;
    }

    public AbstractSqlBuilder filterDataScope(DataScopeHandler dataScopeHandler){
        String permisstionSql = "";
        if(SqlQueryGenerator.hasRule(DataScope.全部.getCode())){
        }else  if(SqlQueryGenerator.hasRule(DataScope.组织树.getCode())&&StringUtils.isNotEmpty(dataScopeHandler.getOrgTreeSql())){
            permisstionSql = dataScopeHandler.getOrgTreeSql();
            this.getParmMap().putAll(dataScopeHandler.getOrgTreeParmMap());
        }else if(SqlQueryGenerator.hasRule(DataScope.组织.getCode())&&StringUtils.isNotEmpty(dataScopeHandler.getOrgSql())){
            permisstionSql = dataScopeHandler.getOrgSql();
            this.getParmMap().putAll(dataScopeHandler.getOrgParmMap());
        }else if(SqlQueryGenerator.hasRule(DataScope.个人.getCode())&&StringUtils.isNotEmpty(dataScopeHandler.getPersonalSql())){
            permisstionSql = dataScopeHandler.getPersonalSql();
            this.getParmMap().putAll(dataScopeHandler.getPersonalParmMap());
        }

        if(StringUtils.isNotEmpty(permisstionSql)){
            this.append(" and ");
            if(!StringUtils.isEmpty(dataScopeHandler.getCustomSql())){
                this.append(" (").append(permisstionSql).append(" ").append(dataScopeHandler.getCustomSql()).append(") ");
                this.getParmMap().putAll(dataScopeHandler.getCustomParmMap());
            }else{
                this.append(permisstionSql);
            }
        }
        return this;
    }

    public <T> AbstractSqlBuilder joinCondition(T entity, String alias) {
        return joinCondition(entity, alias, null);
    }

    public <T> AbstractSqlBuilder joinCondition(T entity, String alias, Map<String, String[]> map){
        if(map==null){
            ServletRequestAttributes servletRequestAttributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (servletRequestAttributes != null) {
                HttpServletRequest request = servletRequestAttributes.getRequest();
                map = request.getParameterMap();
            }
        }
        if(sql.indexOf("where")==-1){
            sql.append(" where 1=1 ");
        }
        SqlQueryGenerator.installMplus(this,entity,map,alias);
        return this;
    }

    @Override
    public String toString() {
        return sql.toString();
    }

    public String getSql() {
        if(StringUtils.isNotEmpty(this.orderBy)){
            sql.append(" order by ").append(this.orderBy);
        }
        return sql.toString();
    }

    public Pageable getPage() {
        return page;
    }

    public String getCountSql() {
        if(StringUtils.isNotEmpty(countSql)){
            return countSql.toString();
        }else{
            String result = "";
            int from = sql.toString().toLowerCase().indexOf("from");
            if(from!=-1){
                result = "select count(1) "+sql.substring(from);
            }
            return result;
        }
    }

    public AbstractSqlBuilder countSql(StringBuilder countSql) {
        this.countSql = countSql;
        return this;
    }

    public Class getReturnType() {
        return returnType;
    }

    public String getOrderBy() {
        return orderBy;
    }


    public AbstractSqlBuilder setParmsLikeLeft(String key,Object value){
        getParmMap().put(key,"%"+value);
        return this;
    }
    public AbstractSqlBuilder setParmsLikeRight(String key,Object value){
        getParmMap().put(key,value+"%");
        return this;
    }

    public AbstractSqlBuilder appendField(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" = :").append(paramName).setParms(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldGE(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" >= :").append(paramName).setParms(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldGT(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" > :").append(paramName).setParms(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldLT(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" < :").append(paramName).setParms(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldLE(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" <= :").append(paramName).setParms(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldLike(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" like :").append(paramName).setParmsLike(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldNE(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" <> :").append(paramName).setParmsLike(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldLikeLeft(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" like :").append(paramName).setParmsLikeLeft(paramName,value);
        return this;
    }
    public AbstractSqlBuilder appendFieldLikeRight(String fieldName,Object value,String alias,String paramName){
        String tableAlias = alias == null ? "" : alias + ".";
        paramName=StringUtils.isNotEmpty(paramName)?paramName:fieldName;
        this.append(" and ").append(tableAlias).append(fieldName).append(" like :").append(paramName).setParmsLikeRight(paramName,value);
        return this;
    }
    public AbstractSqlBuilder orderBy(String orderBy) {
        this.orderBy = orderBy;
        return this;
    }

    /**
     * 自定义sql
     */
    public AbstractSqlBuilder assembleCustomRule(){
        if(this.getSql().indexOf("where")==-1){
            this.append(" where 1=1 ");
        }
        Map<String, SysPermissionDataRuleModel> ruleMap = SqlQueryGenerator.getRuleMap();

        //权限规则自定义SQL表达式
        for (String c : ruleMap.keySet()) {
            if(oConvertUtils.isNotEmpty(c) && c.startsWith(SqlQueryGenerator.SQL_RULES_COLUMN)){
                this.append(" and "+SqlQueryGenerator.getSqlRuleValue(ruleMap.get(c).getRuleValue()));
            }
        }
        return this;
    }
}
